﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Windows.Markup;
using System.Linq;

namespace Slex.Lib.Interactions
{
    /// <summary>
    /// An action to invoke a method in the model
    /// </summary>
    [ContentProperty("Parameters")]
    public class InvokeMethodAction : TargettedTriggerAction
    {
        public string MethodName
        {
            get { return (string)GetValue(MethodNameProperty); }
            set { SetValue(MethodNameProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MethodName.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MethodNameProperty =
            DependencyProperty.Register("MethodName", typeof(string), typeof(InvokeMethodAction), new PropertyMetadata(string.Empty));


        public object Result
        {
            get { return (object)GetValue(ResultProperty); }
            internal set { SetValue(ResultProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Result.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ResultProperty =
            DependencyProperty.Register("Result", typeof(object), typeof(InvokeMethodAction), new PropertyMetadata(null));

        


        /// <summary>
        /// A set of parameters this method will take
        /// </summary>
        public ActionParameters Parameters
        {
            get { return (ActionParameters)GetValue(MethodParametersProperty); }
            set { SetValue(MethodParametersProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Conditions.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MethodParametersProperty =
            DependencyProperty.Register("Parameters", typeof(ActionParameters), typeof(InvokeMethodAction), new PropertyMetadata(null));

        


        /// <summary>
        /// Invoke this command conditionally, based on conditions provided
        /// </summary>
        /// <param name="parameter"></param>
        internal override void InvokeConditional(object parameter)
        {
            
            if (Target != null)
            {
                var method = Target.GetType().GetMethod(MethodName);
                if (method == null) throw new InvalidOperationException("Unable to find Method " + MethodName);


                List<object> convertedParams = new List<object>();
                if (null != Parameters)
                {
                    var methodParams=method.GetParameters();
                    if (methodParams.Length!=Parameters.Count)
                        throw new InvalidOperationException("Method parameters don't match with given parameters for " + MethodName);

                    int i=0;
                    foreach (var p in Parameters)
                    {
                        convertedParams.Add(ConverterHelper.ConvertToType(p.PropertyValue,methodParams[i].ParameterType));
                    }

                    method.Invoke(Target, convertedParams.ToArray());
                }
                else
                {
                    method.Invoke(Target,null);
                }
            }
        }


        /// <summary>
        /// Internally initialize this action
        /// </summary>
        internal override void InternalInitialize()
        {
            base.InternalInitialize();

            if (Parameters != null)
            {
                Parameters.ToList().ForEach(p =>
                { p.TriggerContext = TriggerContext; p.AssociatedObject = this.AssociatedObject; p.InternalInitialize(); });
            }
        }

    }
}
